/**
 * 全站 http 配置
 *
 * axios参数说明
 * isSerialize是否开启form表单提交
 * isToken是否需要token
 */
import axios from 'axios'
import store from '@/store/';
import router from '@/router/'
import {ElMessage} from 'element-plus'
import {getToken, setToken} from '@/utils/auth'
import {signUtil} from '@/utils/sign-util'
import website from '@/config/website';
// progress bar
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

// 默认请求超时时间
axios.defaults.timeout = 10000 * 5;

//返回其他状态吗
axios.defaults.validateStatus = function (status) {
    return status >= 200 && status <= 500; // 默认的
};


// 跨域请求，允许保存cookie
axios.defaults.withCredentials = true;

// NProgress Configuration
NProgress.configure({
    showSpinner: false
});

// 用于跟踪错误消息是否已经显示的标志
let errorMessageDisplayed = false;
// 错误消息（没有登录/登录过期 防重复）显示的时间间隔（单位：毫秒）
const displayTimeout = 3000;

//HTTP request拦截
axios.interceptors.request.use(config => {
    NProgress.start();

    // 让所有请求默认携带token--['Authorization']为自定义key 请根据实际情况自行修改
    config.headers[website.Authorization] = getToken();

    // 参数加签
    let timestamp = new Date().getTime();
    let sign = signUtil(config.url, config.params, config.data, timestamp)
    config.headers['timestamp'] = `${timestamp}`;
    config.headers['sign'] = `${sign}`;
    return config;
}, error => {
    return Promise.reject(error)
});


//HTTP response拦截
axios.interceptors.response.use(res => {
    // console.debug(res.config.url, "  =》 res:", res)
    NProgress.done();
    // 响应状态处理
    respStatusHandler(res);
    // 下载文件处理
    if ((res.data != null && res.data instanceof Blob)) {
        return respBlobHandler(res);
    } else if (res.data.code === 200) {
        // 统一处理业务code码
        res = respSuccessHandler(res)
    } else {
        // 响应非200
        respErrorHandler(res);
    }
    return res;
}, error => {
    NProgress.done();
    return Promise.reject(new Error(error));
});

/**
 * 文件响应处理
 * @param res
 */
function respBlobHandler(res) {
    // 判断文件导出是否成功
    const reader = new FileReader();
    reader.readAsText(res.data, 'utf-8');
    reader.onload = function () {
        try {
            // 是json /表示服务器出现错误
            const resJson = JSON.parse(reader.result);
            ElMessage({message: resJson.msg, type: 'error'});
            return Promise.reject(new Error(resJson.msg))
        } catch (e) {
            // 是正常的文件
        }
    }
    return res;
}


/**
 * 成功逻辑
 * @param res
 */
function respSuccessHandler(res) {
    if (res.config != null && res.config.method !== "get" && res.config.method !== "GET") {
        ElMessage({message: res.data.msg, type: 'success'})
    }
    // 自动刷新 token 来进行续期
    if (res.headers[website.Authorization] !== undefined && res.headers[website.Authorization] !== null) {
        let newToken = res.headers[website.Authorization];
        setToken(newToken);
    }
    return res;
}

/**
 * 失败逻辑
 * @param res
 * @returns {Promise<never>}
 */
function respErrorHandler(res) {
    // 请求失败
    // 返回 10000 表示没有登录过期, 10001 表示没有登录 跳登录页
    if (res.data.code === 10000 || res.data.code === 10001) {
        // 退出登录 // 在n秒内不重复显示此错误提示, 指定时间后重置标志，允许再次显示错误消息
        if (!errorMessageDisplayed) {
            ElMessage({message: res.data.msg, type: 'error'});
            errorMessageDisplayed = true;
            setTimeout(() => {
                errorMessageDisplayed = false;
            }, displayTimeout);
        }
        store.dispatch("LogOut").then(() => {
            router.push({path: "/login"});
        });
        return Promise.reject(new Error(res.data.msg))
    }
    // 非10000 直接抛后台给的错误提示信息
    ElMessage({message: res.data.msg, type: 'error'});
    return Promise.reject(new Error(res.data.msg))
}


/**
 * 响应状态处理器
 */
function respStatusHandler(res) {
    const status = Number(res.status) || 200;
    // 如果是401则跳转到登录页面
    if (status === 401) store.dispatch('FedLogOut').then(() => router.push({path: '/login'}));

    // 如果http状态码请求为非 200 状态码默认统一处理
    if (status !== 200) {
        const message = '后台服务走丢了,请稍后重试...';
        ElMessage({message: message, type: 'error'});
        return Promise.reject(new Error(message))
    }
}


export default axios;